package cn.iocoder.yudao.module.system.util;

import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.seg.Segment;
import com.hankcs.hanlp.seg.common.Term;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 中文分词工具类
 * 提供多种中文分词策略，用于将中文文本拆分为有意义的词语
 */
public class ChineseSegmentationUtil {

    /**
     * 常见专业领域关键词
     */
    private static final String[] COMMON_FIELDS = {
            "工程", "技术", "管理", "设计", "科学", "学", "教育", "研究",
            "医学", "经济", "金融", "会计", "法学", "计算机", "软件", "通信",
            "电子", "机械", "土木", "建筑", "化学", "物理", "生物", "数学",
            "艺术", "音乐", "文学", "历史", "哲学", "心理", "语言", "翻译",
            "新闻", "传媒", "广告", "营销", "国际", "贸易", "金融", "证券",
            "保险", "财务", "人力", "资源", "行政", "公共", "政治", "社会",
            "农业", "林业", "水产", "畜牧", "环境", "生态", "地理", "地质",
            "材料", "冶金", "能源", "电力", "自动化", "智能", "信息", "网络",
            "安全", "测控", "仪器", "制造", "工业", "食品", "药学", "护理",
            "康复", "临床", "预防", "中医", "西医", "口腔", "眼科", "外科",
            "内科", "儿科", "妇产", "精神", "神经", "肿瘤", "影像", "检验",
            "麻醉", "急诊", "重症", "康复", "理疗", "营养", "心理", "健康"
    };

    /**
     * 常见分隔符正则表达式
     */
    private static final Pattern SEPARATOR_PATTERN = Pattern.compile("[\\s与和及、+（）()\\-]");

    /**
     * 中文词语正则表达式（2个或以上的汉字）
     */
    private static final Pattern CHINESE_WORD_PATTERN = Pattern.compile("[\\u4e00-\\u9fa5]{2,}");

    /**
     * 自定义词典文件路径
     */
    private static final String CUSTOM_DICT_PATH = "hanlp-major.txt";

    /**
     * 停用词列表，这些词汇过于广义，不具有强的区分性，应该从分词结果中过滤掉
     */
    private static final Set<String> STOP_WORDS = new HashSet<>(Arrays.asList(
            "技术", "工程", "应用", "管理", "学", "科学", "研究",
            "实验", "实践", "理论", "基础", "实用", "现代", "开发",
            "分析", "设计", "系统", "方法", "方案", "模式", "策略",
            "专业", "方向", "领域", "类", "等", "与", "和", "及"
    ));

    /**
     * HanLP分词器实例，使用自定义配置
     */
    private static final Segment HANLP_SEGMENT;

    static {
        // 初始化HanLP分词器
        HANLP_SEGMENT = HanLP.newSegment()
                .enableNameRecognize(true)     // 开启人名识别
                .enableOrganizationRecognize(true)  // 开启机构名识别
                .enablePlaceRecognize(true)    // 开启地名识别
                .enableCustomDictionary(true)  // 开启自定义词典
                .enablePartOfSpeechTagging(true);  // 开启词性标注

        try {
            // 加载自定义词典
            com.hankcs.hanlp.dictionary.CustomDictionary.add("计算机科学");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("软件工程");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("电子信息");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("大数据");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("人工智能");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("智能化");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("嵌入式");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("物联网");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("云计算");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("数据科学");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("机械工程");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("自动化");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("电气工程");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("土木工程");
            com.hankcs.hanlp.dictionary.CustomDictionary.add("建筑学");

            // 将常见专业领域关键词也添加到自定义词典
            for (String field : COMMON_FIELDS) {
                if (field.length() >= 2) {
                    com.hankcs.hanlp.dictionary.CustomDictionary.add(field);
                }
            }
        } catch (Exception e) {
            // 如果加载失败，不影响程序运行
            System.err.println("初始化HanLP分词器失败: " + e.getMessage());
        }
    }

    /**
     * 使用多种策略对文本进行分词
     *
     * @param text 待分词文本
     * @return 分词结果列表
     */
    public static List<String> segment(String text) {
        if (!StringUtils.hasText(text)) {
            return Collections.emptyList();
        }

        // 首先使用HanLP进行分词
        List<String> keywords = segmentByHanLP(text);

        // 如果HanLP分词结果不理想，尝试使用规则拆分
        if (keywords.size() <= 1 && text.length() > 3) {
            keywords.addAll(segmentByRules(text));
        }

        // 如果规则拆分得到的关键词太少，尝试使用特征拆分
        if (keywords.size() <= 1 && text.length() > 3) {
            keywords.addAll(segmentByCharacteristics(text));
        }

        // 如果仍然没有足够的关键词，尝试使用长度拆分
        if (keywords.size() <= 1 && text.length() > 4) {
            keywords.addAll(segmentByLength(text));
        }

        // 去重
        return new ArrayList<>(new LinkedHashSet<>(keywords));
    }

    /**
     * 使用HanLP进行分词
     *
     * @param text 待分词文本
     * @return 分词结果列表
     */
    public static List<String> segmentByHanLP(String text) {
        if (!StringUtils.hasText(text)) {
            return Collections.emptyList();
        }

        try {
            // 使用HanLP进行分词
            List<Term> terms = HANLP_SEGMENT.seg(text);

            // 提取分词结果，过滤掉太短的词、非中文词和停用词
            List<String> words = terms.stream()
                    .map(term -> term.word) // 使用term.word字段
                    .filter(word -> word.length() >= 2) // 过滤掉单字
                    .filter(word -> word.matches(".*[\\u4e00-\\u9fa5]+.*")) // 必须包含中文字符
                    .filter(word -> !STOP_WORDS.contains(word)) // 过滤掉停用词
                    .collect(Collectors.toList());

            // 如果过滤后没有关键词，考虑保留原始的分词结果（不过滤停用词）
            if (words.isEmpty() && !terms.isEmpty()) {
                words = terms.stream()
                        .map(term -> term.word)
                        .filter(word -> word.length() >= 2)
                        .filter(word -> word.matches(".*[\\u4e00-\\u9fa5]+.*"))
                        .collect(Collectors.toList());
            }

            return words;
        } catch (Exception e) {
            // 如果HanLP分词出错，返回空列表
            return Collections.emptyList();
        }
    }

    /**
     * 使用规则拆分文本
     *
     * @param text 待拆分文本
     * @return 拆分结果
     */
    public static List<String> segmentByRules(String text) {
        if (!StringUtils.hasText(text)) {
            return Collections.emptyList();
        }

        List<String> result = new ArrayList<>();

        // 按照分隔符拆分
        String[] parts = SEPARATOR_PATTERN.split(text);
        for (String part : parts) {
            if (StringUtils.hasText(part) && part.length() >= 2 && !STOP_WORDS.contains(part.trim())) {
                result.add(part.trim());
            }
        }

        // 如果过滤后没有关键词，考虑保留原始的分词结果（不过滤停用词）
        if (result.isEmpty() && parts.length > 0) {
            for (String part : parts) {
                if (StringUtils.hasText(part) && part.length() >= 2) {
                    result.add(part.trim());
                }
            }
        }

        // 提取文本中的中文词语（2个或以上的汉字）
        if (result.isEmpty()) {
            Matcher matcher = CHINESE_WORD_PATTERN.matcher(text);
            while (matcher.find()) {
                String word = matcher.group();
                if (!result.contains(word)) {
                    result.add(word);
                }
            }
        }

        return result;
    }

    /**
     * 根据文本特征进行拆分
     *
     * @param text 待拆分文本
     * @return 拆分结果
     */
    public static List<String> segmentByCharacteristics(String text) {
        if (!StringUtils.hasText(text)) {
            return Collections.emptyList();
        }

        List<String> result = new ArrayList<>();

        // 检查文本中是否包含常见领域关键词
        for (String field : COMMON_FIELDS) {
            // 跳过停用词
            if (STOP_WORDS.contains(field)) {
                continue;
            }

            if (text.contains(field) && !result.contains(field)) {
                // 提取关键词前的部分
                int index = text.indexOf(field);
                if (index > 1) {
                    String prefix = text.substring(0, index);
                    if (prefix.length() >= 2 && !result.contains(prefix) && !STOP_WORDS.contains(prefix)) {
                        result.add(prefix);
                    }
                }

                // 提取关键词后的部分
                int endIndex = index + field.length();
                if (endIndex < text.length() - 1) {
                    String suffix = text.substring(endIndex);
                    if (suffix.length() >= 2 && !result.contains(suffix) && !STOP_WORDS.contains(suffix)) {
                        result.add(suffix);
                    }
                }

                // 添加领域关键词
                result.add(field);
            }
        }

        // 如果过滤后没有关键词，考虑保留原始的分词结果（不过滤停用词）
        if (result.isEmpty()) {
            for (String field : COMMON_FIELDS) {
                if (text.contains(field) && !result.contains(field)) {
                    result.add(field);
                }
            }
        }

        return result;
    }

    /**
     * 根据文本长度进行拆分
     *
     * @param text 待拆分文本
     * @return 拆分结果
     */
    public static List<String> segmentByLength(String text) {
        if (!StringUtils.hasText(text)) {
            return Collections.emptyList();
        }

        List<String> result = new ArrayList<>();
        int length = text.length();

        // 根据文本长度采用不同的拆分策略
        if (length == 4) {
            // 2-2拆分
            result.add(text.substring(0, 2));
            result.add(text.substring(2, 4));
        } else if (length == 5) {
            // 2-3拆分
            result.add(text.substring(0, 2));
            result.add(text.substring(2, 5));
        } else if (length == 6) {
            // 3-3拆分
            result.add(text.substring(0, 3));
            result.add(text.substring(3, 6));
        } else if (length > 6) {
            // 对于更长的文本，提取前3个字符和后3个字符
            result.add(text.substring(0, 3));
            result.add(text.substring(length - 3));

            // 如果长度大于9，尝试提取中间部分
            if (length > 9) {
                int middleStart = 3;
                int middleEnd = length - 3;
                if (middleEnd - middleStart >= 2) {
                    result.add(text.substring(middleStart, middleEnd));
                }
            }
        }

        return result;
    }

    /**
     * 使用N-Gram算法进行分词
     * N-Gram是一种基于统计的分词方法，将文本切分为连续的N个字符
     *
     * @param text 待分词文本
     * @param n N-Gram中的N值，通常为2或3
     * @return 分词结果
     */
    public static List<String> segmentByNGram(String text, int n) {
        if (!StringUtils.hasText(text) || text.length() < n) {
            return Collections.emptyList();
        }

        List<String> result = new ArrayList<>();
        for (int i = 0; i <= text.length() - n; i++) {
            String gram = text.substring(i, i + n);
            result.add(gram);
        }

        return result;
    }

    /**
     * 使用双向最大匹配算法进行分词
     * 该方法结合了正向最大匹配和逆向最大匹配的结果
     *
     * @param text 待分词文本
     * @param dict 词典
     * @return 分词结果
     */
    public static List<String> segmentByBiDirectionalMaxMatch(String text, Set<String> dict) {
        if (!StringUtils.hasText(text)) {
            return Collections.emptyList();
        }

        // 如果词典为空，使用默认的常见领域关键词作为词典
        if (dict == null || dict.isEmpty()) {
            dict = new HashSet<>(Arrays.asList(COMMON_FIELDS));
        }

        // 正向最大匹配
        List<String> forwardResult = new ArrayList<>();
        int start = 0;
        while (start < text.length()) {
            int maxEnd = Math.min(start + 5, text.length()); // 最大匹配长度为5
            String matchedWord = null;

            for (int end = maxEnd; end > start; end--) {
                String word = text.substring(start, end);
                if (dict.contains(word)) {
                    matchedWord = word;
                    break;
                }
            }

            if (matchedWord == null) {
                // 如果没有匹配到词典中的词，则将单个字符作为一个词
                matchedWord = text.substring(start, start + 1);
            }

            forwardResult.add(matchedWord);
            start += matchedWord.length();
        }

        return forwardResult;
    }
}
